home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Nebula 1
/
Nebula One.iso
/
Internet
/
WWW
/
gform.1.1
/
gform.c
< prev
next >
Wrap
C/C++ Source or Header
|
1996-02-03
|
16KB
|
733 lines
/***
* gform - A generic HTML form decoder
*
* It takes a HTML form file and scans
* this file for comments beginning with <!--gform ....>
* These are taken to be formatting info and delivery commands
* for gform.
*
* See gform.txt for description and samples
*
* Swinburne University of Technology and the author will not be
* responsible for any damages or loss suffered or incurred by
* any user or any other person arising in any way from the use
* of this software. No warranty of any kind, either express or
* implied is given. You may copy, modify and redistribute it.
*
* Ver 1.1e harry@swin.edu.au 8-Nov-95 Swinburne University
*
* Contibutions:
* jem@sunsite.unc.edu University of North Caroline
*
* See CHANGES for change history.
***/
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <ctype.h>
#include <time.h>
#include <string.h>
#include "config.h"
#define bzero(s,n) memset(s,0,n)
#include <stdlib.h>
#define LEN 4096
/* keywords for gform */
#define DELIVER "DELIVER" /* indicates delivery method */
#define MAIL "MAIL" /* a delivery method */
#define FFILE "FILE" /* a delivery method */
#define PRINT "PRINT" /* Send to printer */
#define SUBJECT "SUBJECT" /* Subject of mail mesg */
#define REPLY "REPLY" /* reply to form submission */
#define GFORM_TAG "<!GFORM " /* gform command line keyword */
#define GFORM_TAG2 "<!--GFORM " /* gform command line keyword */
/* commandline parsing states */
#define NSTATE 0 /* NULL state */
#define TSTATE 1 /* text string with variables */
#define SKIP_WHITE(a) while (isspace(*a)) a++
struct entry {
char *name;
char *val;
struct entry *next;
};
/* from cgi-bin/util.c */
char *fmakeword();
char *makeword();
void unescape_url();
void plustospace();
char *tildeexpand();
/* func prototypes */
char *decode_commands();
char *command();
void print_header();
char *strnupr();
void error();
char *insert_value();
char *do_escapes();
int send_to_file();
int isendtag();
char *get_html_filename();
char *get_cmd_val();
struct entry *entries, *head;
int state, linecount, printit=0;
char *outfile, *address, *subject, DEFSUBJECT[256],
*queue, *replyfile, *webhome, date[12], ttime[12];
main(argc, argv)
int argc;
char *argv[];
{
int len,i, line[LEN];
char s[256], *word, *buf, *tmp, *tmp2, *fname;
FILE *f1;
setdate(date, ttime);
if (strcmp(getenv("REQUEST_METHOD"),"POST")!=0)
error("This program should be referenced with the method=POST\n",0);
if (strcmp(getenv("CONTENT_TYPE"),
"application/x-www-form-urlencoded")!=0)
error("This program can only be used to decode forms\n",0);
len = atoi(getenv("CONTENT_LENGTH"));
entries = NULL; replyfile=NULL;
outfile = NULL; subject=NULL; address=NULL;
/* Get document root directory */
if ((webhome = getenv("DOCUMENT_ROOT"))==NULL)
#if defined(WEBHOME)
webhome=WEBHOME;
#endif
if (webhome==NULL)
error("Failed to get DOCUMENT_ROOT directory. Define WEBHOME in the config.h file",0);
/* Grab all the variable names and data from the form */
for(i=0;len && (!feof(stdin));i++) {
if (entries) {
entries->next = (struct entry *) malloc(sizeof(struct entry));
entries=entries->next;
} else {
entries = (struct entry *) malloc(sizeof(struct entry));
head = entries;
}
/* stick all the fields of the HTML Form into the entries struct */
entries->val = fmakeword(stdin,'&',&len);
plustospace(entries->val);
unescape_url(entries->val);
word = (char *) makeword(entries->val, '=');
entries->name = strnupr(word, strlen(word));
entries->next=NULL;
}
/* We now have all the data from the form, now decode the
'GFORM' commands from the HTML form file */
fname = get_html_filename();
buf = decode_commands(fname);
sprintf(DEFSUBJECT,"Form [%s] submission" ,fname);
/* Now deliver the results */
if (outfile) /* Results to a file */
send_to_file(outfile,buf);
if (address) /* or results thru the mail */
send_email(address,subject,buf);
if (printit) /* straight to a printer */
send_to_printer(queue, buf);
if (replyfile) { /* The HTML file to reply with */
#ifdef USERDIR
for (tmp2=replyfile; *replyfile=='/'; replyfile++);
if (*replyfile == '~')
tmp2=tildeexpand(replyfile);
else {
#endif
tmp2 = (char *) malloc(strlen(webhome)+strlen(replyfile)+1);
if (*replyfile=='/') replyfile++;
sprintf(tmp2,"%s/%s",webhome,replyfile);
#ifdef USERDIR
}
#endif
if ((f1 = fopen(tmp2,"r"))==NULL) {
sprintf(s,"Opening Replyfile: %s not found",replyfile);
error(s,0);
} else {
print_header();
while (fread(line,1,LEN,f1)!=0)
fprintf(stdout,"%s",line);
}
fclose(f1);
} else { /* A default thank you reply */
print_header();
printf("<BODY>");
printf("<TITLE>Thank you</TITLE>");
printf("<H3>Thank you</H3>");
printf("</BODY>");
}
return(0);
}
/***
* decode_commands
* Read the HTML form file and look for commands
* Replace variables, translate escaped chars
* and return the results
*
***/
char *decode_commands(fname)
char *fname;
{
FILE *f1;
int BRACKET=0,j,escape, vl, variable, endvar=0;
char line[LEN], *commandline,*start, *end, *trace,
*word,
msg[64], tmp[256],
*buf, /* The buf of formatted output */
*vp,
*p,
ch;
if ((f1 = fopen(fname,"r")) == NULL) {
#ifdef USERDIR
sprintf(tmp,"File not found: %s",fname);
#else
sprintf(tmp,"File not found: %s<BR>('~' expansion not enabled)",fname);
#endif
error(tmp,0);
}
linecount=0;
buf = (char *) malloc(1);
*buf=0;
bzero(line, LEN);
while (fgets(line,LEN, f1) !=NULL) {
linecount++;
state=NSTATE;
if (!(commandline = command(line))) continue;
/* fixup any escaped chars */
commandline = do_escapes(commandline);
SKIP_WHITE(commandline);
/* A formatting command line */
if ((state==NSTATE) && (*commandline == '"')) {
state = TSTATE;
start = commandline+1;
trace=start; end=NULL;
variable=0; escape=0;
for (;*trace && !end;trace++) {
if (*trace=='"') {
end = trace;
*trace=0;
if (variable) {
variable=0; start=trace;
buf = insert_value(buf,vp,vl);
} else {
buf = (char *) realloc(buf, strlen(buf)+
(trace-start)+1);
strncat(buf, start , (trace-start));
}
state=NSTATE;
if (BRACKET)
error("Missing bracket",linecount);
} else if (variable && *trace == ')') {
BRACKET--;
endvar=1;
vl--;
} else if (variable) {
if ((isspace(*trace) || end || endvar) && !BRACKET) {
variable=0; start=trace;
buf = insert_value(buf,vp,vl);
endvar=0;
} else
vl++;
} else if (*trace=='$') {
variable=1; vl=0;
vp = trace+1;
if (*vp == '(') {
vp++;
BRACKET++;
}
buf = (char *) realloc(buf, strlen(buf) +
(trace-start)+1);
strncat(buf, start , (trace-start));
start = vp;
}
}
} /* end of formatting command lines */
else /* now check command keywords */
if (state==NSTATE) {
if (strcmp(strnupr(commandline,strlen(DELIVER)),
DELIVER)==0) {
commandline=commandline+strlen(DELIVER);
SKIP_WHITE(commandline);
if (*commandline != '=')
error("Missing '='",linecount);
commandline++;
SKIP_WHITE(commandline);
/* Handle the FILE delivery command */
if (strcmp(strnupr(commandline,strlen(FFILE)),FFILE)==0) {
commandline=commandline+strlen(FFILE);
SKIP_WHITE(commandline);
if (*commandline !='"')
error("\" Expected ",linecount);
else
outfile=get_cmd_val(commandline);
state=NSTATE;
/* Handle the PRINT delivery command */
} else if (strcmp(strnupr(commandline,strlen(PRINT)),PRINT)==0) {
commandline=commandline+strlen(PRINT);
SKIP_WHITE(commandline);
if (isendtag(commandline))
queue=0;
else if (*commandline !='"')
error("\" Expected ",linecount);
else
queue = get_cmd_val(commandline);
printit=1;
state=NSTATE;
/* Handle the MAIL delivery command */
} else if (strcmp(strnupr(commandline, strlen(MAIL)),MAIL)==0) {
commandline=commandline+strlen(MAIL);
SKIP_WHITE(commandline);
if (*commandline!='"')
error("\" Expected ",linecount);
else {
address=get_cmd_val(commandline);
commandline+=strlen(commandline)+1;
}
SKIP_WHITE(commandline);
if (strcmp(strnupr(commandline,strlen(SUBJECT)),SUBJECT)==0) {
commandline=commandline+strlen(SUBJECT);
SKIP_WHITE(commandline);
if (*commandline!='=')
error("= Expected",linecount);
commandline++;
SKIP_WHITE(commandline);
if (*commandline!='"')
error("\" Expected ",linecount);
else
subject=get_cmd_val(commandline);
} else
subject=DEFSUBJECT;
state=NSTATE;
} else {
sprintf(msg,"Expected %s, %s or %s\n",
FFILE, PRINT, MAIL);
error(msg, linecount);
}
/* Handle REPLY command */
} else if (strcmp(strnupr(commandline,strlen(REPLY)), REPLY)==0) {
commandline=commandline+strlen(REPLY);
SKIP_WHITE(commandline);
if (*commandline != '=')
error("Missing '='",linecount);
commandline++;
SKIP_WHITE(commandline);
if (*commandline != '"')
error("\" Expected ",linecount);
else
replyfile=get_cmd_val(commandline);
state=NSTATE;
} else
error("Commandline syntax, check \"",linecount);
}
if (state==TSTATE)
error("Missing \"",linecount);
bzero(line, LEN);
} /* end of lines */
fclose(f1);
/* Handle Escaped '$' and '"' that have been turned into
char 1 and 2 with do_escapes(). Handled last as not to interfere
with the parsing of commandline
*/
for (j=0;j<strlen(buf);j++)
if (*(buf+j)==1)
*(buf+j) = '$';
else if (*(buf+j)==2)
*(buf+j) = '"';
return(buf);
}
/**
* insert_value
* replace a variable with its value
*
**/
char *insert_value(buf, vp, vl)
char *buf, *vp;
int vl;
{
char *word, msg[64], *envvar;
int hit=0;
word = strnupr(vp,vl);
entries=head;
while (entries) {
if (strcmp(word,entries->name)==0) {
buf = (char *) realloc(buf,strlen(buf) + strlen(entries->val)+4); /* 3 is to allow for ", " when multiple results */
if (hit)
strcat(buf,", ");
strcat(buf,entries->val);
hit++;
}
entries=entries->next;
}
/* if variable is not found in the list of variables, try environement
variables */
if (!hit)
if (strcmp(word, "DATE")==0) {
buf = (char *) realloc(buf,strlen(buf) +
strlen(date)+1);
strcat(buf, date);
} else if (strcmp(word,"TIME")==0) {
buf = (char *) realloc(buf,strlen(buf) +
strlen(ttime)+1);
strcat(buf, ttime);
} else if ((envvar = getenv(word))!=NULL) {
buf = (char *) realloc(buf,strlen(buf) +
strlen(envvar)+1);
strcat(buf, envvar);
} else { /* Nothing found */
buf = (char *) realloc(buf, strlen(buf) + 5);
strcat(buf,"null");
}
return(buf);
}
/***
* do_escapes
* Replaces all escaped chars with actual char its escaped.
*
***/
char* strdup(s)
{
unsigned long len;
char* copy = NULL;
if (s == NULL) /* saftey check to postpone stupid errors */
return(NULL);
len = strlen(s); /* length of string - terminator */
copy = (char*)malloc((size_t)(sizeof(char)*(len + 1)));
strncpy(copy,s,len + 1);
return(copy);
}
char *do_escapes(line)
char *line;
{
char *p, *tmp, *top;
p = strdup(line);
if ((tmp = (char *) malloc(2 * strlen(line)))==NULL)
return(NULL);
top = tmp;
while (*p) {
if (*p=='\\') {
p++;
switch (*p) {
case 'n' : *p = 10; break;
case 't' : *p = 8; break;
case 'r' : *p = 13; break;
case 'f' : *p = 12; break;
case '$' : *p = 1; break; /* special case */
case '"' : *p = 2; break; /* special case */
}
}
*(tmp++) = *(p++);
}
return(top);
}
/***
* command
* Looks for a 'gform' commandline.
* Returns the uppercase commandline (less the leading command tag
* or NULL if it is not a commandline.
* For backword compatibility, the old GFORM_TAG is still supported
* but not really correct.
*
***/
char *command(line)
char *line;
{
char *commandline, *word, *word2;
word = strnupr(line,strlen(GFORM_TAG));
word2 = strnupr(line,strlen(GFORM_TAG2));
if (strncmp(GFORM_TAG, word,strlen(GFORM_TAG))==0) {
commandline=line+strlen(GFORM_TAG);
return(commandline);
} else if (strncmp(GFORM_TAG2, word2,strlen(GFORM_TAG2))==0) {
commandline=line+strlen(GFORM_TAG2);
return(commandline);
} else
return(NULL);
}
/***
* send_to_file
* Send buffer to a file
*
***/
int send_to_file(fname, buf)
char *fname, *buf;
{
FILE *f;
if ((f = fopen(fname,"a")) == NULL)
return(0);
fprintf(f,"%s",buf);
fclose(f);
return(1);
}
/***
* print_header
* Prints the required header for http stuff
*
***/
void print_header()
{
printf("Content-type: text/html\n\n");
return;
}
/***
* strnupr
* takes a character string and converts 'len' into
* uppercase. It then returns a pointer to the uppercase
* chars.
***/
char *strnupr(line, len)
char *line;
int len;
{
int i;
char *newline;
newline = (char *) malloc(len + 1);
for (i=0;i<len;i++)
*(newline+i) = toupper(line[i]);
*(newline+len) = '\0';
return(newline);
}
/***
* isendtag(cgar *p)
* Returns 1 if p is pointing to an end-of-comment tag
*
***/
int isendtag(p)
char *p;
{
char *q = p;
if (q) {
if (*q=='-' && q+1 && *(q+1)=='-' && q+2) {
q+=2;
SKIP_WHITE(q);
}
if (*q=='>')
return(1);
}
return(0);
}
/***
* get_html_filename()
* Returns the filename of the FORM that called us.
*
***/
char *get_html_filename()
{
static char http[]="HTTP://";
char *tmp, *path, *p, *uref, *referer = getenv("HTTP_REFERER");
char s[256];
struct stat fstat;
if (referer==NULL) {
referer=getenv("QUERY_STRING");
if (referer==NULL)
error("Could not get environment", 0);
}
p = referer;
if (strlen(referer)>6) {
uref = strnupr(referer,7);
if (strncmp(http,uref,7)==0) {
p = referer+7;
while (p && *p!='/') p++; /* skip host */
p++;
}
}
for (tmp=p; *p=='/'; p++);
#ifdef USERDIR
if (*p=='~') {
tmp=tildeexpand(p);
if (!tmp) {
sprintf(s,"Unable to expand: %s",p);
error(s,0);
} else if (stat(tmp,&fstat)) {
sprintf(s,"File not Found: %s",tmp);
error(s,0);
}
return(tmp);
} else {
#endif
path = (char *) malloc(strlen(webhome)+
(tmp==NULL ? 0: strlen(tmp)) + 2);
sprintf(path, "%s/%s",webhome, tmp);
return(path);
#ifdef USERDIR
}
#endif
}
/***
* get_cmd_val(string)
* Returns a string between quotes , less the quotes
*
***/
char *get_cmd_val(s)
char *s;
{
char *p;
p = s+1;
while (*p && *p!='"') p++;
if (!*p)
error("\" Expected ",linecount);
*p=0;
return(s+1);
}
/***
* setdate()
*
* Sets 2 variables to the current date and time
*
***/
setdate(date, ttime)
char *date, *ttime;
{
time_t t;
struct tm *ttm;
static char *months[]={"Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug","Sep","Oct","Nov","Dec" };
t=time(0);
ttm = localtime(&t);
sprintf(ttime, "%.2d:%.2d:%.2d",ttm->tm_hour, ttm->tm_min,ttm->tm_sec);
sprintf(date,"%2d-%s-%2d",ttm->tm_mday, months[ttm->tm_mon],ttm->tm_year);
}
/***
* error
* Prints a simple error message back to the user
*
***/
void error(msg, linecount)
char *msg;
int linecount;
{
print_header();
if (linecount)
printf("<P>gform: Error (line %d) %s<P>\n",linecount,msg);
else
printf("<P>gform: Error %s<P>\n",msg);
exit(1);
}